﻿using Microsoft.Data.Sqlite;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Linq;
using System.Globalization;

namespace SQLite
{
    internal static class ExType
    {

        /// <summary>
        /// 类型映射
        /// </summary>
        private static readonly Dictionary<Type, SqliteType> _sqliteTypeMapping = new Dictionary<Type, SqliteType>()
        {
            {typeof(bool), SqliteType.Integer},
            {typeof(byte),SqliteType.Integer},
            {typeof(byte[]), SqliteType.Blob},
            {typeof(char),SqliteType.Integer},
            {typeof(DateTime), SqliteType.Text},
            {typeof(DateTimeOffset), SqliteType.Text},
            {typeof(DBNull), SqliteType.Text},
            {typeof(decimal),SqliteType.Text},
            {typeof(double), SqliteType.Real},
            {typeof(float), SqliteType.Real},
            {typeof(Guid), SqliteType.Text},
            {typeof(int), SqliteType.Integer},
            {typeof(long), SqliteType.Integer},
            {typeof(sbyte),SqliteType.Integer},
            {typeof(short), SqliteType.Integer},
            {typeof(string), SqliteType.Text},
            {typeof(TimeSpan), SqliteType.Text},
            {typeof(uint), SqliteType.Integer},
            {typeof(ulong), SqliteType.Integer},
            {typeof(ushort), SqliteType.Integer},
        };


        /// <summary>
        /// 获取类型
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static SqliteType GetSqliteType(object value)
        {
            if (value == null)
            {
                return SqliteType.Text;
            }

            var type = value.GetType().UnwrapNullableType().UnwrapEnumType();
            if (_sqliteTypeMapping.TryGetValue(type, out var sqliteType))
            {
                return sqliteType;
            }
            else
            {
                throw new InvalidOperationException($"未知{nameof(type)}类型");
            }
        }


        /// <summary>
        /// 获取类型
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static SqliteType GetSqliteType(Type type)
        {
            var stype = type.UnwrapNullableType().UnwrapEnumType();
            if (_sqliteTypeMapping.TryGetValue(stype, out var sqliteType))
            {
                return sqliteType;
            }
            else
            {
                throw new InvalidOperationException($"未知{nameof(type)}类型");
            }
        }


        /// <summary>
        /// 将c#值转换成sqlite的值
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string ConvertSqliteString(object value)
        {
            if (value == null)
            {
                return "NULL";
            }
            else
            {
                var type = value.GetType();
                if (type == typeof(short) ||
                    type == typeof(int) ||
                    type == typeof(long) ||
                    type == typeof(float) ||
                    type == typeof(double) ||
                    type == typeof(decimal) ||
                    type == typeof(byte) ||
                    type == typeof(sbyte) ||
                    type == typeof(uint) ||
                    type == typeof(ulong) ||
                    type == typeof(ushort)
                    )
                {
                    return $"{value}";
                }
                else if (type == typeof(Guid) || type == typeof(string))
                {
                    return $"'{value}'";
                }
                else if (type == typeof(bool))
                {
                    return $"{((bool)value ? 1 : 0)}";
                }
                else if (type == typeof(DateTime))
                {
                    return $"'{(((DateTime)value).ToString(@"yyyy\-MM\-dd HH\:mm\:ss.FFFFFFF", CultureInfo.InvariantCulture))}'";
                }
                else if (type == typeof(DateTimeOffset))
                {
                    return $"'{(((DateTimeOffset)value).ToString(@"yyyy\-MM\-dd HH\:mm\:ss.FFFFFFFzzz", CultureInfo.InvariantCulture))}'";
                }
                else if (type == typeof(TimeSpan))
                {
                    return $"'{(((TimeSpan)value).ToString("c"))}'";
                }
                else
                {
                    return $"'{value}'";
                }
            }
        }



        public static bool IsNullable(this Type type)
          => !type.IsValueType
             || (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>));

        public static Type UnwrapEnumType(this Type type)
            => type.GetTypeInfo().IsEnum ? Enum.GetUnderlyingType(type) : type;

        public static Type UnwrapNullableType(this Type type)
            => Nullable.GetUnderlyingType(type) ?? type;
    }
}
